#ifndef __INC_SBCSX_H__
#define __INC_SBCSX_H__

#if _MSC_VER
#pragma once
#pragma warning(push)
#pragma warning(disable:4127)
#pragma warning(disable:4251)
#endif

#ifdef __cplusplus

#include "sbhs.h"
#include "sbctn.h"

//
class kObj;

//////////////////////////////////////////////////////////////////////////
// cs automation

// mutex
class kMutexLock
{
	KCH_SELF(kMutexLock);

public:
	static kMutexLock* New()
	{
		return (kMutexLock*)k_mutex_new();
	}

	static kMutexLock* New(kint count)
	{
		return (kMutexLock*)k_mutex_new_count(count);
	}

	void Delete()
	{
		k_mutex_delete((kMutex*)this);
	}

	void Enter()
	{
		k_mutex_enter((kMutex*)this);
	}

	void Leave()
	{
		k_mutex_leave((kMutex*)this);
	}

public:
	class ScopedLock
#ifdef _MSC_VER
		: private tpl::NoCopyClass
#endif
	{
	private:
		kMutexLock* _l;

	public:
		explicit ScopedLock(kMutexLock* l) : _l(l)
		{
			l->Enter();
		}

		explicit ScopedLock(kMutex* l) : _l((kMutexLock*)l)
		{
			_l->Enter();
		}

		~ScopedLock()
		{
			_l->Leave();
		}
	};
};
#define kGuardMutex(a)			if (tpl::LockPtrGuard<kMutexLock> _slm = (a)) k_assert_0(0); else

//
class kSpinLock
{
public:
	kLock _l;

public:
	kSpinLock(kLock l = KLOCK_INIT) : _l(l)
	{
	}

	bool Try()
	{
		return k_lock_try(&_l) != 0;
	}

	void Enter()
	{
		k_lock_enter(&_l);
	}

	void Leave()
	{
		k_lock_leave(&_l);
	}

public:
	class ScopedLock
#ifdef _MSC_VER
		: private tpl::NoCopyClass
#endif
	{
	private:
		kSpinLock& _l;

	public:
		explicit ScopedLock(kSpinLock& l) : _l(l)
		{
			l.Enter();
		}

		~ScopedLock()
		{
			_l.Leave();
		}
	};
};
#define kGuardSpinLock(a)		if (tpl::LockGuard<kSpinLock> _slm = (a)) k_assert_0(0); else

// symbol
class KAPI kSymbol
{
	KCH_SELF(kSymbol);

public:
	kuint				_sym;

public:
	kSymbol() : _sym(0) {}
	explicit kSymbol(kuint sym) : _sym(sym) {}
	kSymbol(const kSymbol& right) : _sym(right._sym) {}

	kSymbol& operator=(const kSymbol& right) { _sym = right._sym; return *this; }
	kSymbol& operator=(kuint right) { _sym = right; return *this; }
	bool operator==(const kSymbol& right) const { return _sym == right._sym; }
	bool operator!=(const kSymbol& right) const { return _sym != right._sym; }

	operator kuint() const { return _sym; }

	//
	explicit kSymbol(const char* str, bool isstatic = false);

	const char* String() const;
	kint Length() const;
	kuint Value() const;
	void Set(kuint sym);
	void Set(const char* str, bool isstatic = false);
};

// type management
class KAPI kTmnt
{
	KCH_SELF(kTmnt);
	KCH_SEAL(kTmnt);

public:
	static kType GetType(const kchar* name);
	static kType FindType(const kSymbol& sym);
	static kTypeInfo* LookType(kType type);
	static kType Register(const kchar* name, const kTypeDecl& decl, kType parent);
	static void DebugPrint(bool usetree = false);
};

// type stub
class KAPI kTsb
{
	KCH_SELF(kTsb);

private:
	kType _type;

public:
	kTsb() : _type(0) {}
	kTsb(kType type) : _type(type) {}
	kTsb(const kTsb& right) : _type(right._type) {}

	kTsb& operator=(const kTsb& right) { this->_type = right._type; return *this; }
	bool operator==(const kTsb& right) { return this->_type == right._type; }
	bool operator!=(const kTsb& right) { return this->_type != right._type; }
	operator kType() { return _type; }

	kTypeInfo* GetInfo() const;
	const kchar* GetName() const;
	const kchar* GetDesc() const;
	kuint GetSymbol() const;
	kint GetId() const;
	kbool IsValue() const;
	kbool IsRef() const;
	kint GetSize() const;
	kint GetRoam() const;
	kint GetFlags(kint mask = 0) const;
	kint GetSupers() const;
	kint GetChildren() const;
	kTsb GetChildNth(kint nth) const;
	kTsb GetParent() const;
	khOpFunc GetOp(kint op);
	kbool FindOp(kint op, khParamDesc** param, khOpFunc* opf);
	khParamDesc* GetParam(const kchar* name) const;
	khParamDesc* FindParam(const kSymbol& sym) const;
	kvoid SetDesc(const kchar* desc);
	kvoid SetRoam(kint roam);
	kvoid SetFuncConstruct(khCnstFunc func);
	kvoid SetFuncDispose(khDispFunc func);
	kvoid SetFuncKey(khKeyFunc func);
	kvoid SetFuncHash(khHashFunc func);
	kvoid SetFuncEq(khEqFunc func);
	kbool SetOps(kint op, khOpFunc opf);
	kbool SetOpTable(const khOpTable& opt);
	kbool BindParam(kint id, khParamDesc* param);
	kint BindProps(kint baseid, kint count, const khParamPropReg* regs);
	kint BindFuncs(kint baseid, kint count, const khParamFuncReg* regs);
};


//////////////////////////////////////////////////////////////////////////
// object

//
#define _KT_SPP_ENTRY(cls,name,flags) {\
	static volatile kType K_CONCAT(cls, _type) = 0; \
	if (k_once_try(&K_CONCAT(cls, _type))) {\
		kType ret = k_tmnt_entry(name, super_type::Type(), sizeof(cls), flags, \
		&cls::TypeInitialize, &cls::TypeFinalize, &cls::BaseConstruct, &cls::BaseDispose); \
		k_once_leave(&K_CONCAT(cls, _type), ret); }\
	return K_CONCAT(cls, _type); }
#define _KT_SPP_CONSTRUCT(cls) { cls* self = static_cast<cls*>(ptr); ::new(self)cls(); return self; }
#define _KT_SPP_DISPOSE(cls) { cls* self = static_cast<cls*>(ptr); self->~cls(); return self; }

// declare for sub class (header)
#define KT_DECL_TYPE_INIT(cls)				protected: static void TypeInitialize(kType type) throw()
#define KT_DECL_TYPE_FINAL(cls)				protected: static void TypeFinalize(kType type) throw()
#define KT_DECL_CONSTRUCT(cls)				protected: static kBase* BaseConstruct(kpointer ptr) throw()
#define KT_DECL_DISPOSE(cls)				protected: static kpointer BaseDispose(kBase* ptr) throw()
#define KT_DECL_ENTRY(cls)					public: static kType Type() throw()

// implement for sub class (code)
#define KT_IMPL_TYPE_INIT(cls)				void cls::TypeInitialize(kType) throw() {}
#define KT_IMPL_TYPE_FINAL(cls)				void cls::TypeFinalize(kType) throw() {}
#define KT_IMPL_CONSTRUCT(cls)				kBase* cls::BaseConstruct(kpointer ptr) throw() _KT_SPP_CONSTRUCT(cls)
#define KT_IMPL_CONSTRUCT_ABSTRACT(cls)		kBase* cls::BaseConstruct(kpointer) throw() { return NULL; }
#define KT_IMPL_DISPOSE(cls)				kpointer cls::BaseDispose(kBase* ptr) throw() _KT_SPP_DISPOSE(cls)
#define KT_IMPL_ENTRY(cls,name,flags)		kType cls::Type() throw() _KT_SPP_ENTRY(cls,name,flags)

// implement for auto class (header)
#define KT_INCL_TYPE_INIT(cls)				KT_DECL_TYPE_INIT(cls) {}
#define KT_INCL_TYPE_FINAL(cls)				KT_DECL_TYPE_FINAL(cls) {}
#define KT_INCL_CONSTRUCT(cls)				KT_DECL_CONSTRUCT(cls) _KT_SPP_CONSTRUCT(cls)
#define KT_INCL_CONSTRUCT_ABSTRACT(cls)		KT_DECL_CONSTRUCT(cls) { return NULL; }
#define KT_INCL_DISPOSE(cls)				KT_DECL_DISPOSE(cls) _KT_SPP_DISPOSE(cls)
#define KT_INCL_ENTRY(cls,name,flags)		KT_DECL_ENTRY(cls) _KT_SPP_ENTRY(cls,name,flags)

//
#define KCH_CLASS(cls,spr)					KCH_BASE(cls,spr); KCH_FRIEND(kCrbs)
#define KCH_TYPE(cls,type)					KT_DECL_ENTRY(cls) { return type; }

// sub class
#define KCH_SUBCLASS(cls,spr)				KCH_CLASS(cls,spr); KT_DECL_ENTRY(cls); KT_DECL_CONSTRUCT(cls); KT_DECL_DISPOSE(cls)

#define KIMPL_SUBCLASS(cls,name)			KT_IMPL_ENTRY(cls,name,0); KT_IMPL_CONSTRUCT(cls); KT_IMPL_DISPOSE(cls)
#define KIMPL_SUBCLASS_SEALED(cls,name)		KT_IMPL_ENTRY(cls,name,KTIF_SEALED); KT_IMPL_CONSTRUCT(cls); KT_IMPL_DISPOSE(cls)
#define KIMPL_SUBCLASS_ABSTRACT(cls,name)	KT_IMPL_ENTRY(cls,name,KTIF_ABSTRACT); KT_IMPL_CONSTRUCT_ABSTRACT(cls); KT_IMPL_DISPOSE(cls)

// auto class
#define KCH_AUTOCLASS(cls,spr,name)			KCH_CLASS(cls,spr); KT_INCL_ENTRY(cls,name,0); KT_INCL_CONSTRUCT(cls); KT_INCL_DISPOSE(cls)
#define KCH_AUTOCLASS_SEALED(cls,spr,name)	KCH_CLASS(cls,spr); KT_INCL_ENTRY(cls,name,KTIF_SEALED); KT_INCL_CONSTRUCT(cls); KT_INCL_DISPOSE(cls)
#define KCH_AUTOCLASS_ABSTRACT(cls,spr,name) KCH_CLASS(cls,spr); KT_INCL_ENTRY(cls,name,KTIF_ABSTRACT); KT_INCL_CONSTRUCT_ABSTRACT(cls); KT_INCL_DISPOSE(cls)

// macro version of crbs
#define kobj_create(type)					static_cast<type*>(kCrbs::Create(type::Type()))
#define kobj_new(type,...)					kCrbs::New<type>(__VA_ARGS__)
#define kobj_load(obj)						((obj) ? (obj)->Load() : 0)
#define kobj_unload(obj)					((obj) ? (obj)->Unload() : 0)
#define kobj_reset(pobj)					K_STMT_BEGIN{if (*(pobj)) { (*(pobj))->Unload(); *(pobj)=NULL;}}K_STMT_END

#define kunk_add_ref(com)					((com) ? (com)->AddRef() : 0)
#define kunk_release(com)					((com) ? (com)->Release() : 0)
#define kunk_reset(pcom)					K_STMT_BEGIN{if (*(pcom)) { (*(pcom))->Release(); *(pcom)=NULL;}}K_STMT_END

// trace macro for derived class of kObj
#define kobj_trace(l,txt)					K_STMT_BEGIN{if (l>=k_getlv()) k_mesg_trace(l,type_info->name,txt);}K_STMT_END
#define kobj_traces(l,txt)					K_STMT_BEGIN{if (l>=k_getlv()) k_mesgs_trace(l,type_info->name,txt);}K_STMT_END
#define kobj_tracef(l,fmt,...)				K_STMT_BEGIN{if (l>=k_getlv()) k_mesgf_trace(l,type_info->name,fmt,__VA_ARGS__);}K_STMT_END
#define kobj_tracep(l,code)					K_STMT_BEGIN{if (l>=k_getlv()) {if (l>=KLV_WARNING) k_mesgp_trace(l,type_info->name,code,__FILE__,__LINE__); else k_mesgp_trace(l,type_info->name,code,NULL,0);}}K_STMT_END
#define kobj_tracet(l,code,txt)				K_STMT_BEGIN{if (l>=k_getlv()) {if (l>=KLV_WARNING) k_mesgt_trace(l,type_info->name,code,txt,__FILE__,__LINE__); else k_mesgt_trace(l,type_info->name,code,txt,NULL,0);}}K_STMT_END

#define _K_TMPL_TYPE_CCK(TYPE, ptr)			K_STMT_BEGIN{ TYPE* r = (TYPE*)k_crbs_check(TYPE::Type(), ptr); if (r) { return r; } else { delete ptr; return NULL; } }K_STMT_END

// creation
class KAPI kCrbs
{
	KCH_SELF(kCrbs);
	KCH_SEAL(kCrbs);

public:
	static kObj* Create(kType type) throw();
	static void Delete(kObj* base) throw();
	static void ForceDelete(kObj* base) throw();

public:
	template <typename TYPE>
	inline static TYPE* New() throw()
	{
		TYPE* p = new TYPE();
		_K_TMPL_TYPE_CCK(TYPE, p);
	}

	template <typename TYPE, typename A1>
	inline static TYPE* New(A1 a1) throw()
	{
		TYPE* p = new TYPE(a1);
		_K_TMPL_TYPE_CCK(TYPE, p);
	}

	template <typename TYPE, typename A1, typename A2>
	inline static TYPE* New(A1 a1, A2 a2) throw()
	{
		TYPE* p = new TYPE(a1, a2);
		_K_TMPL_TYPE_CCK(TYPE, p);
	}

	template <typename TYPE, typename A1, typename A2, typename A3>
	inline static TYPE* New(A1 a1, A2 a2, A3 a3) throw()
	{
		TYPE* p = new TYPE(a1, a2, a3);
		_K_TMPL_TYPE_CCK(TYPE, p);
	}

	template <typename TYPE, typename A1, typename A2, typename A3, typename A4>
	inline static TYPE* New(A1 a1, A2 a2, A3 a3, A4 a4) throw()
	{
		TYPE* p = new TYPE(a1, a2, a3, a4);
		_K_TMPL_TYPE_CCK(TYPE, p);
	}

	template <typename TYPE, typename A1, typename A2, typename A3, typename A4, typename A5>
	inline static TYPE* New(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) throw()
	{
		TYPE* p = new TYPE(a1, a2, a3, a4, a5);
		_K_TMPL_TYPE_CCK(TYPE, p);
	}

	template <typename TYPE, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>
	inline static TYPE* New(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) throw()
	{
		TYPE* p = new TYPE(a1, a2, a3, a4, a5, a6);
		_K_TMPL_TYPE_CCK(TYPE, p);
	}

	template <typename TYPE, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7>
	inline static TYPE* New(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) throw()
	{
		TYPE* p = new TYPE(a1, a2, a3, a4, a5, a6, a7);
		_K_TMPL_TYPE_CCK(TYPE, p);
	}
};

// base object
class KAPI kObj : public kBase
{
	KCH_SELF(kObj);
	KCH_NOEC(kObj);
	KCH_TYPE(kObj, KTYPE_BASE);
	KCH_AVOID_FOR_INTERFACE(kObj);

protected:
	kObj() {}

public:
	virtual kint KCALL Signal(const char* sig, kpointer arg) { (void)sig; (void)arg; return 0; }

	kint Load();
	kint Unload();

	kObj* PtrLoad();
	kObj* PtrUnload();

	kvoid ForceUnload();
	kvoid ForceRevive();

	kint GetRef();
	kType GetType();
	kTypeInfo* GetTypeInfo();
	kpointer GetUserData();
	kpointer SetUserData(kpointer data);

protected:
	KT_DECL_TYPE_INIT(cls);
	KT_DECL_TYPE_FINAL(cls);

public:
	void* operator new(size_t size, const char* file, int line) throw();
	void* operator new(size_t size) throw();
	void* operator new[](size_t size, const char* file, int line) throw();
	void* operator new[](size_t size) throw();
	void operator delete(void* ptr, const char*, int) throw();
	void operator delete(void* ptr) throw();
	void operator delete[](void* ptr, const char*, int) throw();
	void operator delete[](void* ptr) throw();
};

// node object
class KAPI kObjNode : public kObj
{
	KCH_BASE(kObjNode, kObj);
	KCH_FRIEND(kObjList);
	KCH_FRIEND(kObjMukum);
	KCH_FRIEND(kObjMukumImpl);
	KCH_TYPE(kObjNode, KTYPE_NODE);

protected:
	kuintptr			_node_desc;
	ksize_t				_node_hash;
	kObjNode*			_node_prev;
	kObjNode*			_node_next;
	kObjNode*			_node_sib;

protected:
	kObjNode() {};
	~kObjNode() {};

public:
	kuintptr GetDescription() { return _node_desc; }
	ksize_t NodeHash() { return _node_hash; }
	kObjNode* NodePrev() { return _node_prev; }
	kObjNode* NodeNext() { return _node_next; }
	kObjNode* NodeSibiling() { return _node_sib; }
};

// test object
class KAPI kObjTest : public kObj
{
	KCH_SUBCLASS(kObjTest, kObj);

private:
	kint				t_val;

public:
	kObjTest();
	~kObjTest();

public:
	kint GetValue();
	void SetValue(kint value);
};


//////////////////////////////////////////////////////////////////////////
// container

// object list
class kObjList : tpl::MemBase
{
public:
	typedef tpl::_iter::NodeListConstIterator<kObjNode> ConstIterator;
	typedef tpl::_iter::NodeListIterator<kObjNode> Iterator;

public:
	ksize_t			_count;
	kObjNode*		_frst;
	kObjNode*		_last;

public:
	void Initialize()
	{
		_count = 0;
		_frst = _last = NULL;
	}

	void Dispose(bool bycommon = true)
	{
		if (bycommon)
		{
			kObjNode* next;
			for (kObjNode* node = _frst; node; node = next)
			{
				next = node->_node_next;
				node->ForceUnload();
			}
		}
		else
		{
			for (;;)
			{
				kObjNode* node = _frst;
				if (!node)
					break;
				node->ForceUnload();
			}
		}
	}

	void Clear(bool byforce = true)
	{
		kObjNode* next;

		if (byforce)
		{
			for (kObjNode* node = _frst; node; node = next)
			{
				next = node->_node_next;
				node->ForceUnload();
			}
		}
		else
		{
			for (kObjNode* node = _frst; node; node = next)
			{
				next = node->_node_next;

				if (node->Unload() != 0)
				{
					node->_node_next = NULL;
					node->_node_prev = NULL;
				}
			}
		}

		_count = 0;
		_frst = _last = NULL;
	}

	void Append(kObjNode* node)
	{
		if (_frst)
			_frst->_node_prev = node;
		else
			_last = node;

		node->_node_next = _frst;
		node->_node_prev = NULL;
		_frst = node;
		_count++;
	}

	void Prepend(kObjNode* node)
	{
		if (_last)
			_last->_node_next = node;
		else
			_frst = node;

		node->_node_prev = _last;
		node->_node_next = NULL;
		_last = node;
		_count++;
	}

	void Remove(kObjNode* node)
	{
		if (node->_node_next)
			node->_node_next->_node_prev = node->_node_prev;
		else
			_last = node->_node_prev;

		if (node->_node_prev)
			node->_node_prev->_node_next = node->_node_next;
		else
			_frst = node->_node_next;

		_count--;
	}

	void RemoveFirst()
	{
		Remove(_last);
	}

	void RemoveLast()
	{
		Remove(_frst);
	}

	bool Contains(kObjNode* item) const
	{
		for (kObjNode* node = _frst; node; node = node->_node_next)
		{
			if (node == item)
				return true;
		}

		return false;
	}

	bool IsHave() const
	{
		return _count > 0;
	}

	bool IsEmpty() const
	{
		return _count == 0;
	}

	kint Count() const
	{
		return (kint)_count;
	}

	Iterator First()
	{
		return Iterator(_last);
	}

	Iterator Last()
	{
		return Iterator(_frst);
	}

	Iterator Begin()
	{
		return Iterator(_last);
	}

	Iterator End()
	{
		return Iterator(NULL);
	}

	ConstIterator ConstFirst() const
	{
		return ConstIterator(_last);
	}

	ConstIterator ConstLast() const
	{
		return ConstIterator(_frst);
	}

	ConstIterator ConstBegin() const
	{
		return ConstIterator(_last);
	}

	ConstIterator ConstEnd() const
	{
		return ConstIterator(NULL);
	}

	Iterator first()
	{
		return Iterator(_last);
	}

	Iterator last()
	{
		return Iterator(_frst);
	}

	Iterator begin()
	{
		return Iterator(_last);
	}

	Iterator end()
	{
		return Iterator(NULL);
	}

	ConstIterator cfirst() const
	{
		return ConstIterator(_last);
	}

	ConstIterator clast() const
	{
		return ConstIterator(_frst);
	}

	ConstIterator cbegin() const
	{
		return ConstIterator(_last);
	}

	ConstIterator cend() const
	{
		return ConstIterator(NULL);
	}

	template <typename FN2>
	void ForEach(FN2 fn, kpointer userdata)
	{
		for (kObjNode* node = _last; node; node = node->_node_prev)
			fn(userdata, node);
	}

	template <typename FN>
	void LoopEach(FN fn)
	{
		for (kObjNode* node = _last; node; node = node->_node_prev)
			fn(node);
	}

	template <typename PRED>
	kObjNode* Find(PRED fn)
	{
		for (kObjNode* node = _last; node; node = node->_node_prev)
		{
			if (fn(node))
				return node;
		}

		return NULL;
	}

	template <typename PRED, typename A>
	kObjNode* Find(PRED fn, A& arg)
	{
		for (kObjNode* node = _last; node; node = node->_node_prev)
		{
			if (fn(node, arg))
				return node;
		}

		return NULL;
	}
};

// mukum
class kObjMukum
{
public:
	kTypeInfo*			_info;
	ksize_t				_revision;
	ksize_t				_bucket;
	ksize_t				_count;
	kObjNode**			_nodes;

public:
	void Initialize(kType type)
	{
		_info = kTmnt::LookType(type);
		k_assert_0(_info);
		k_assert_0(_info->func_hash);
		k_assert_0(_info->func_eq);

		_revision = 0;
		_count = 0;
		_bucket = K_MIN_HASH;
		_nodes = k_new_zero(K_MIN_HASH, kObjNode*);
	}

	void Dispose(bool bycommon = true)
	{
		if (bycommon)
		{
			for (ksize_t i = 0; i < _bucket; i++)
			{
				kObjNode* next;
				for (kObjNode* node = _nodes[i]; node; node = next)
				{
					next = node->_node_sib;
					node->ForceUnload();
				}
			}
		}
		else
		{
			for (ksize_t i = 0; i < _bucket; i++)
			{
				for (;;)
				{
					kObjNode* node = _nodes[i];
					if (!node)
						break;
					node->ForceUnload();
				}
			}
		}

		k_delete(_nodes);
	}

	template <typename FN2>
	void ForEach(FN2 fn, kpointer userdata)
	{
		for (ksize_t i = 0; i < _bucket; i++)
		{
			for (kObjNode* node = _nodes[i]; node; node = node->_node_sib)
				fn(userdata, node);
		}
	}

	template <typename FN>
	void LoopEach(FN fn)
	{
		for (ksize_t i = 0; i < _bucket; i++)
		{
			for (kObjNode* node = _nodes[i]; node; node = node->_node_sib)
				fn(node);
		}
	}

	ksize_t Count()
	{
		return _count;
	}

	ksize_t Bucket()
	{
		return _bucket;
	}

	ksize_t Revision()
	{
		return _revision;
	}

	bool IsHave()
	{
		return _count > 0;
	}

	bool IsEmpty()
	{
		return _count == 0;
	}

	KAPI void Clear(bool byforce = true);
	KAPI bool Add(kObjNode* node);
	KAPI kObjNode* Get(kconstpointer key);
	KAPI kObjNode* Remove(kconstpointer key);
	KAPI void RemoveNode(kObjNode* node);
};


//////////////////////////////////////////////////////////////////////////
// stream

//
class kMount;

//
class KAPI kStream : public kObj
{
	KCH_SUBCLASS(kStream, kObj);

public:
	typedef tpl::BlueStr<K_MAX_PATH> PathString;

protected:
	kint				_flags;
	kMount*				_mount;
	PathString			_desc;

protected:
	kStream(kint flags = 0);
	~kStream();

public:
	virtual kint Read(kpointer buffer, kint offset, kint size) = 0;
	virtual kint Write(kconstpointer buffer, kint offset, kint size) = 0;

	virtual klong GetSize() = 0;
	virtual kulong Tell() = 0;
	virtual kbool Seek(klong offset, kint org) = 0;

	virtual kbool Flush() = 0;

	const kchar* GetDesc() { return _desc.Data(); }
	kMount* GetMount() { return _mount; }
	kint GetFlags(kint mask = 0) { return K_OMASK(_flags, mask); }
	kbool CanRead() { return (_flags & KFF_READ) != 0; }
	kbool CanWrite() { return (_flags & KFF_WRITE) != 0; }
	kbool CanSeek() { return (_flags & KFF_SEEK) != 0; }

	void SetDesc(const char* desc) { _desc = desc; }
	void SetMount(kMount* mnt);
};

// memory stream
class KAPI kMemoryStream : public kStream
{
	KCH_SUBCLASS(kMemoryStream, kStream);
	KCH_FRIEND(kHfs);

protected:
	kbyte*				_data;
	ksize_t				_capa;
	ksize_t				_size;
	ksize_t				_loc;

protected:
	kMemoryStream();
	~kMemoryStream();

public:
	K_OVR kint Read(kpointer buffer, kint offset, kint size);
	K_OVR kint Write(kconstpointer buffer, kint offset, kint size);

	K_OVR klong GetSize();
	K_OVR kulong Tell();
	K_OVR kbool Seek(klong offset, kint org);

	K_OVR kbool Flush();

	kbool SetSize(ksize_t size);
	kbool Dump(kStream* stream);

	kpointer ReplaceExtern(kpointer buffer, kint capacity, kint size);

public:
	static kMemoryStream* New(kint initcapa = 0);
	static kMemoryStream* NewExtern(kpointer buffer, kint capacity, kint size);
};

// indirect stream
class KAPI kIndirectStream : public kStream
{
	KCH_SUBCLASS(kIndirectStream, kStream);

protected:
	kFile*				_file;
	ksize_t				_indi;
	ksize_t				_size;
	ksize_t				_loc;

protected:
	kIndirectStream();
	~kIndirectStream();

public:
	K_OVR kint Read(kpointer buffer, kint offset, kint size);
	K_OVR klong GetSize();
	K_OVR kulong Tell();
	K_OVR kbool Seek(klong offset, kint org);

	// indirect stream is read only
	K_OVR kint Write(kconstpointer /*buffer*/, kint /*offset*/, kint /*size*/) { return 0; }
	K_OVR kbool Flush() { return false; }

public:
	static kIndirectStream* NewExtern(kFile* file, ksize_t indi, ksize_t size);
};

// file stream
class KAPI kFileStream : public kStream
{
	KCH_SUBCLASS(kFileStream, kStream);

protected:
	kFile*				_file;

protected:
	kFileStream();
	~kFileStream();

public:
	K_OVR kint Read(kpointer buffer, kint offset, kint size);
	K_OVR kint Write(kconstpointer buffer, kint offset, kint size);

	K_OVR klong GetSize();
	K_OVR kulong Tell();
	K_OVR kbool Seek(klong offset, kint org);

	K_OVR kbool Flush();

	kFile* GetInternalFile() { return _file; }

public:
	static kFileStream* New(const kchar* filename, const kchar* mode = NULL);
	static kFileStream* NewMount(const kchar* filename, const kchar* mode, kMount* mount);
};


//////////////////////////////////////////////////////////////////////////
// mount

// file list
class KAPI kFileList : public kObj
{
	KCH_SUBCLASS(kFileList, kObj);

protected:
	typedef tpl::VecArray<kFileInfo> FileArray;

protected:
	kMount*				_mount;
	char				_dir[K_MAX_PATH];

	kint				_index;
	FileArray*			_infos;

protected:
	kFileList();
	~kFileList();

public:
	kbool First(kFileInfo* info);
	kbool Next(kFileInfo* info);
	kbool Current(kFileInfo* info);

	kint Count();
	kint Index();
};

// mount base
class KAPI kMount : public kObj
{
	KCH_SUBCLASS(kMount, kObj);

public:
	typedef tpl::BlueStr<K_MAX_PATH> PathString;

protected:
	PathString			_desc;
	PathString			_path;

protected:
	kMount();
	~kMount();

public:
	virtual kint IsExist(const kchar* path) = 0;
	virtual kbool Remove(const kchar* path) = 0;

	virtual kbool SetDir(const kchar* dir) = 0;
	virtual kbool MakeDir(const kchar* dir) = 0;

	virtual kStream* OpenFile(const kchar* path, const kchar* mode) = 0;
	virtual kStream* OpenFileIndirect(const char* path) = 0;

	virtual kpointer ReadFile(const kchar* path, kint* size) = 0;

	virtual kFileList* Files(const kchar* mask = NULL) = 0;
	virtual kchar* ExtractPath(const kchar* path) = 0;

	//
	const kchar* GetDesc() { return _desc.Data(); }
	const kchar* GetDir() { return _path.Data(); }

	//
	static kStream* FileOpen(kMount* mnt, const kchar* filename, const kchar* mode = NULL);
	static kStream* FileOpenIndirect(kMount* mnt, const kchar* filename);
	static kpointer FileRead(kMount* mnt, const kchar* filename, kint* size = NULL);
	static kchar* FileTextRead(kMount* mnt, const kchar* filename, kint* size = NULL, kint* codepage = NULL);
	static kchar* BuildName(kMount* mnt, const kchar* path);
	static kchar* BuildPath(kMount* mnt, const kchar* path);

public:
	virtual kpointer SourceRead(const kFileSource& /*src*/) { return NULL; }
	virtual kStream* SourceOpen(const kFileSource& /*src*/, bool /*preload*/) { return NULL; }
};

// disk mount
class KAPI kDiskFs : public kMount
{
	KCH_SUBCLASS(kDiskFs, kMount);

protected:
	kint				_count;

protected:
	kDiskFs();
	~kDiskFs();

public:
	K_OVR kint IsExist(const kchar* path);
	K_OVR kbool Remove(const kchar* path);

	K_OVR kbool SetDir(const kchar* dir);
	K_OVR kbool MakeDir(const kchar* dir);

	K_OVR kStream* OpenFile(const kchar* path, const kchar* mode);
	K_OVR kStream* OpenFileIndirect(const char* path);

	K_OVR kpointer ReadFile(const kchar* path, kint* size);

	K_OVR kFileList* Files(const kchar* mask);
	K_OVR kchar* ExtractPath(const kchar* path);

public:
	static kDiskFs* New(const kchar* dir);
};

// hfs
class KAPI kHfs : public kMount
{
	KCH_SUBCLASS(kHfs, kMount);

public:
	typedef tpl::VecArray<kHfsFile> FileArray;

protected:
	kStream*			_stream;

	FileArray*			_hds;

	kbool				_canwrite;
	kbool				_ismem;

protected:
	kHfs();
	~kHfs();

public:
	K_OVR kint IsExist(const kchar* path);
	K_OVR kbool Remove(const kchar* path);

	K_OVR kbool SetDir(const kchar* dir);
	K_OVR kbool MakeDir(const kchar* dir);

	K_OVR kStream* OpenFile(const kchar* path, const kchar* mode);
	K_OVR kStream* OpenFileIndirect(const char* path);

	K_OVR kpointer ReadFile(const kchar* path, kint* size);

	K_OVR kFileList* Files(const kchar* mask);
	K_OVR kchar* ExtractPath(const kchar* path);

	//
	kbool CanWrite() { return _canwrite; }
	kbool IsMemory() { return _ismem; }
	kStream* GetStream() { return _stream; }
	const FileArray* GetHandles() { return _hds; }

	kbool StoreBuffer(const kchar* filename, kpointer buffer, kint size, kint store = KSTORE_AUTO);
	kbool StoreStream(const kchar* filename, kStream* stream, kint store = KSTORE_AUTO);
	kbool StoreFile(const kchar* newname, kMount* mnt, const kchar* filename, kint store = KSTORE_AUTO);

	kbool Optimize(const kchar* outputfilename, const tpl::Function<void(int, const kchar*)>& stackfn);
	kbool Optimize(const kchar* outputfilename);

protected:
	K_OVR kpointer SourceRead(const kFileSource& src);
	K_OVR kStream* SourceOpen(const kFileSource& src, bool preload);

public:
	static kHfs* New(const kchar* filename, const kchar* mode = NULL);
};


//////////////////////////////////////////////////////////////////////////
// 
class KAPI kFuse : public kDiskFs
{
	KCH_SUBCLASS(kFuse, kDiskFs);

protected:
	kFuse();
	~kFuse();

public:
	// kFuse is for file open & read
	// directory functions are all disabled;
	K_OVR kbool SetDir(const kchar* /*dir*/) { return false; }
	K_OVR kbool MakeDir(const kchar* /*dir*/) { return false; }
	K_OVR kFileList* Files(const kchar* /*mask*/) { return NULL; }

	//
	//K_OVR kint IsExist(const kchar* path) = 0;
	//K_OVR kbool Remove(const kchar* path) = 0;
	//K_OVR kStream* OpenFile(const kchar* path, const kchar* mode) = 0;
	//K_OVR kpointer ReadFile(const kchar* path, kint* size) = 0;

	//
	virtual bool AddMount(const char* path) = 0;
	virtual kint GetMountCount() = 0;

	kint AutoMount(const char* mask = NULL);

public:
	static kFuse* New(const char* basedir = NULL);
};

#endif	// __cplusplus

#if _MSC_VER
#pragma warning(pop)
#endif

#endif	// __INC_SBCSX_H__
